package com.pb.wkflow.core.factor.behavior;

import com.pb.infra.oth.util.SpringContextUtil;
import lombok.extern.slf4j.Slf4j;
import org.camunda.bpm.engine.impl.bpmn.behavior.ParallelMultiInstanceActivityBehavior;
import org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity;
import org.camunda.bpm.engine.impl.pvm.PvmActivity;
import org.camunda.bpm.engine.impl.pvm.delegate.ActivityExecution;
import org.camunda.bpm.engine.impl.pvm.runtime.Callback;
import org.camunda.bpm.engine.impl.pvm.runtime.PvmExecutionImpl;

import java.util.ArrayList;
import java.util.List;

import static com.pb.wkflow.core.config.Constants.NUMBER_OF_PASS_INSTANCES;


/**
 * 并行会签解析行为
 * @author 苗益辉
 * @date 2022/5/18 9:35
 */
@Slf4j
public class MyParallelMultiInstanceActivityBehavior extends ParallelMultiInstanceActivityBehavior {

    @Override
    public void execute(ActivityExecution execution) throws Exception {
        log.info("MyParallelMultiInstanceActivityBehavior executionId：{},activityId： {}",
                execution.getId(), execution.getCurrentActivityId());
        DefaultMultiInstanceActivityBehavior behavior = SpringContextUtil.getBean(DefaultMultiInstanceActivityBehavior.class);
        behavior.defaultExecute(execution);
        super.execute(execution);
    }

    @Override
    protected void createInstances(ActivityExecution execution, int nrOfInstances) throws Exception {
        PvmActivity innerActivity = getInnerActivity(execution.getActivity());
        prepareScopeExecution(execution, nrOfInstances);
        setLoopVariable(execution, NUMBER_OF_PASS_INSTANCES, 0);

        List<ActivityExecution> concurrentExecutions = new ArrayList<ActivityExecution>();
        for (int i = 0; i < nrOfInstances; i++) {
            concurrentExecutions.add(createConcurrentExecution(execution));
        }

        for (int i = (nrOfInstances - 1); i >= 0; i--) {
            ActivityExecution activityExecution = concurrentExecutions.get(i);
            performInstance(activityExecution, innerActivity, i);
        }
    }

    /**
     * 表达式涉及 nrOfPassInstances 和 nrOfInstances
     * @param scopeExecution scopeExecution
     * @param endedExecution endedExecution
     */
    @Override
    public void concurrentChildExecutionEnded(ActivityExecution scopeExecution, ActivityExecution endedExecution) {

        int nrOfCompletedInstances = getLoopVariable(scopeExecution, NUMBER_OF_COMPLETED_INSTANCES) + 1;
        setLoopVariable(scopeExecution, NUMBER_OF_COMPLETED_INSTANCES, nrOfCompletedInstances);
        int nrOfActiveInstances = getLoopVariable(scopeExecution, NUMBER_OF_ACTIVE_INSTANCES) - 1;
        setLoopVariable(scopeExecution, NUMBER_OF_ACTIVE_INSTANCES, nrOfActiveInstances);

        // inactivate the concurrent execution
        endedExecution.inactivate();
        endedExecution.setActivityInstanceId(null);

        // join
        scopeExecution.forceUpdate();
        if(completionConditionSatisfied(endedExecution) ||
                allExecutionsEnded(scopeExecution, endedExecution)) {

            ArrayList<ActivityExecution> childExecutions = new ArrayList<ActivityExecution>(((PvmExecutionImpl) scopeExecution).getNonEventScopeExecutions());
            for (ActivityExecution childExecution : childExecutions) {
                // delete all not-ended instances; these are either active (for non-scope tasks) or inactive but have no activity id (for subprocesses, etc.)
                if (childExecution.isActive() || childExecution.getActivity() == null) {
                    ((PvmExecutionImpl)childExecution).deleteCascade("Multi instance completion condition satisfied.");
                } else {
                    childExecution.remove();
                }
            }

            scopeExecution.setActivity((PvmActivity) endedExecution.getActivity().getFlowScope());
            scopeExecution.setActive(true);
            leave(scopeExecution);
        } else {
            ((ExecutionEntity) scopeExecution).dispatchDelayedEventsAndPerformOperation((Callback<PvmExecutionImpl, Void>) null);
        }
    }
}
